//===============================================================================
// XGenPlus Tool
// ==============================================================================
// Please visit http://www.codeplex.com/xgenplus for latest updates.
//
// This source is subject to the GNU General Public License v2.
// 
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Reflection;
using System.Configuration;

namespace XGenPlus.SerializerLib
{
    static class FactoryCache
    {
        static Dictionary<string, ISerializerFactory> factCache = new Dictionary<string, ISerializerFactory>();
        static List<string> nameList = new List<string>(0);
        static bool useTypedSerializers = true;

        /// <summary>
        /// Static Constructor to load all assemblies to the current application domain
        /// </summary>
        static FactoryCache()
        {
            string serializerConfig = ConfigurationManager.AppSettings["UseTypedSerializers"];
            string serializerDllPath = ConfigurationManager.AppSettings["SerializerDllPath"];

            if (null != serializerConfig)
                useTypedSerializers = ("true" == serializerConfig.ToLower());

            if (!useTypedSerializers)
                return;

            //Load all the serializer assemblies to the application domain during intialization
            //which is the fastest way to retreive a serializer type

            Uri uri = new Uri(typeof(FactoryCache).Assembly.CodeBase);
            string path = Path.GetDirectoryName(uri.LocalPath);

            //If serializer dll path is specified, use that instead

            if (null != serializerDllPath && Directory.Exists(serializerDllPath))
                path = serializerDllPath;

            string[] files = Directory.GetFiles(path, "*.Serializers.dll");

            for (int i = 0; i < files.Length; i++)
            {
                try
                {
                    Assembly asm = Assembly.LoadFrom(files[i]);
                    string key = Path.GetFileNameWithoutExtension(asm.Location).Replace(".Serializers", "");
                    string factoryTypeName = key + ".SerializerFactory";
                    ISerializerFactory fact = (ISerializerFactory)asm.CreateInstance(factoryTypeName, true);
                    factCache.Add(key.ToLower(), fact);
                }
                catch { }
            }
            nameList = new List<string>(factCache.Keys);
        }

        public static ISerializerFactory GetFactory(Type t)
        {
            string factoryName = FindBestMatch(t.Namespace);


            if (!string.IsNullOrEmpty(factoryName))
                return factCache[factoryName];
            else
                return null;
        }

        /// <summary>
        /// Finds the best match of a string in a list of items
        /// </summary>
        /// <param name="items">Items to search in</param>
        /// <param name="s">String to compare</param>
        /// <returns></returns>
        private static string FindBestMatch(string s)
        {
            string bestMatch = "";
            int prevLength = 0;

            nameList.ForEach(delegate(string item)
                {
                    if (s.StartsWith(item, StringComparison.InvariantCultureIgnoreCase))
                    {
                        if (item.Length > prevLength)
                        {
                            bestMatch = item;
                            prevLength = item.Length;
                        }
                    }
                }
            );
            return bestMatch;
        }
    }
}
